package com.cook.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cook.dto.recipes.TagsDTO;
import com.cook.entity.RecipeTags;
import com.cook.entity.Tags;
import com.cook.mapper.RecipeTagsMapper;
import com.cook.service.TagsService;
import com.cook.mapper.TagsMapper;
import com.cook.vo.recipes.TagsVO;
import com.cook.vo.recipes.RecipeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author black-white spider
* @description 针对表【tags(食谱标签表)】的数据库操作Service实现
* @createDate 2025-10-27 19:55:23
*/
@Service
@Slf4j
public class TagsServiceImpl extends ServiceImpl<TagsMapper, Tags> implements TagsService {

    @Autowired
    private TagsMapper tagsMapper;

    @Autowired
    private RecipeTagsMapper recipeTagsMapper;

    /**
     * 分页查询标签列表
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @return
     */
    public Map<String, Object> getTagsWithPage(Integer pageNum, Integer pageSize) {
        log.info("分页查询标签列表: pageNum={}, pageSize={}", pageNum, pageSize);

        try {
            int offset = (pageNum - 1) * pageSize;
            List<TagsVO> tagsList = tagsMapper.selectTagsWithPage(offset, pageSize);
            int totalCount = tagsMapper.selectTagsCount();
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            Map<String, Object> result = new HashMap<>();
            result.put("list", tagsList);
            result.put("pageNum", pageNum);
            result.put("pageSize", pageSize);
            result.put("totalCount", totalCount);
            result.put("totalPages", totalPages);

            log.info("分页查询标签成功，共 {} 条数据", tagsList.size());
            return result;

        } catch (Exception e) {
            log.error("分页查询标签列表失败: ", e);
            throw new RuntimeException("查询标签列表失败");
        }
    }


    /**
     * 查询所有标签列表
     */
    public Map<String, Object> getTags() {
        log.info("分页查询标签列表");

        try {
            List<TagsVO> tagsList = tagsMapper.selectTags();
            int totalCount = tagsMapper.selectTagsCount();

            Map<String, Object> result = new HashMap<>();
            result.put("list", tagsList);
            result.put("totalCount", totalCount);

            log.info("查询所有标签成功，共 {} 条数据", tagsList.size());
            return result;

        } catch (Exception e) {
            log.error("分页查询标签列表失败: ", e);
            throw new RuntimeException("查询标签列表失败");
        }
    }

    /**
     * 根据类型查询标签
     * @param type 标签类型
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @return
     */
    public Map<String, Object> getTagsByType(String type, Integer pageNum, Integer pageSize) {
        log.info("根据类型查询标签: type={}, pageNum={}, pageSize={}", type, pageNum, pageSize);

        if (type == null || type.trim().isEmpty()) {
            throw new IllegalArgumentException("标签类型不能为空");
        }

        try {
            int offset = (pageNum - 1) * pageSize;
            List<TagsVO> tagsList = tagsMapper.selectTagsByType(type, offset, pageSize);
            int totalCount = tagsMapper.selectTagsCountByType(type);
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            Map<String, Object> result = new HashMap<>();
            result.put("list", tagsList);
            result.put("pageNum", pageNum);
            result.put("pageSize", pageSize);
            result.put("totalCount", totalCount);
            result.put("totalPages", totalPages);
            result.put("type", type);

            log.info("根据类型查询标签成功，共 {} 条数据", tagsList.size());
            return result;

        } catch (Exception e) {
            log.error("根据类型查询标签失败: ", e);
            throw new RuntimeException("查询标签失败");
        }
    }

    /**
     * 根据标签查询菜谱
     * @param tagId 标签ID
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @return
     */
    public Map<String, Object> getRecipesByTagId(Long tagId, Integer pageNum, Integer pageSize) {
        log.info("根据标签查询菜谱: tagId={}, pageNum={}, pageSize={}", tagId, pageNum, pageSize);

        try {
            int offset = (pageNum - 1) * pageSize;
            List<RecipeVO> recipesList = recipeTagsMapper.selectRecipesByTagId(tagId, offset, pageSize);
            int totalCount = recipeTagsMapper.selectRecipesCountByTagId(tagId);
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            // 获取标签信息
            Tags tag = tagsMapper.selectById(tagId);
            String tagName = tag != null ? tag.getName() : "未知标签";

            Map<String, Object> result = new HashMap<>();
            result.put("list", recipesList);
            result.put("pageNum", pageNum);
            result.put("pageSize", pageSize);
            result.put("totalCount", totalCount);
            result.put("totalPages", totalPages);
            result.put("tagId", tagId);
            result.put("tagName", tagName);

            log.info("根据标签查询菜谱成功，共 {} 条数据", recipesList.size());
            return result;

        } catch (Exception e) {
            log.error("根据标签查询菜谱失败: ", e);
            throw new RuntimeException("查询菜谱失败");
        }
    }

    /**
     * 查询菜谱的标签
     * @param recipeId 菜谱ID
     * @return
     */
    public List<TagsVO> getTagsByRecipeId(Long recipeId) {
        log.info("查询菜谱的标签: recipeId={}", recipeId);

        if (recipeId == null || recipeId <= 0) {
            throw new IllegalArgumentException("菜谱ID不能为空");
        }

        try {
            List<TagsVO> tagsList = recipeTagsMapper.selectTagsByRecipeId(recipeId);
            log.info("查询菜谱标签成功，共 {} 个标签", tagsList.size());
            return tagsList;

        } catch (Exception e) {
            log.error("查询菜谱标签失败: ", e);
            throw new RuntimeException("查询标签失败");
        }
    }

    /**
     * 添加标签
     * @param tagsDTO 标签DTO
     * @return
     */
    @Transactional
    public Long addTag(TagsDTO tagsDTO) {
        log.info("添加标签: name={}, type={}", tagsDTO.getName(), tagsDTO.getType());

        try {
            // 检查标签是否已存在
            Tags existingTag = tagsMapper.selectTagByName(tagsDTO.getName());
            if (existingTag != null) {
                log.warn("标签已存在: {}", tagsDTO.getName());
                throw new RuntimeException("标签名称已存在");
            }

            // DTO 转 Entity
            Tags tag = new Tags();
            BeanUtils.copyProperties(tagsDTO, tag);

            int result = tagsMapper.insertTag(tag);
            if (result > 0) {
                log.info("标签添加成功: tagId={}", tag.getTagId());
                return tag.getTagId();
            } else {
                throw new RuntimeException("添加标签失败");
            }

        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("添加标签失败: ", e);
            throw new RuntimeException("添加标签失败");
        }
    }

    /**
     * 添加菜谱标签关联
     * @param recipeId 菜谱ID
     * @param tagId 标签ID
     * @return
     */
    @Transactional
    public boolean addRecipeTag(Long recipeId, Long tagId) {
        log.info("添加菜谱标签关联: recipeId={}, tagId={}", recipeId, tagId);

        try {
            // 检查关联是否已存在
            int exists = recipeTagsMapper.checkRecipeTagExists(recipeId, tagId);
            if (exists > 0) {
                log.warn("菜谱标签关联已存在: recipeId={}, tagId={}", recipeId, tagId);
                throw new RuntimeException("关联已存在");
            }

            RecipeTags recipeTag = new RecipeTags();
            recipeTag.setRecipeId(recipeId);
            recipeTag.setTagId(tagId);

            int result = recipeTagsMapper.insertRecipeTag(recipeTag);
            boolean success = result > 0;

            if (success) {
                log.info("菜谱标签关联添加成功");
            } else {
                log.warn("菜谱标签关联添加失败");
            }

            return success;

        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("添加菜谱标签关联失败: ", e);
            throw new RuntimeException("添加关联失败");
        }
    }

    /**
     * 删除标签
     * @param tagId 标签ID
     * @return
     */
    @Transactional
    public boolean deleteTag(Long tagId) {
        log.info("删除标签: tagId={}", tagId);

        try {
            // 先删除所有关联的菜谱标签
            recipeTagsMapper.deleteAllRecipeTagsByTagId(tagId);

            // 再删除标签
            int result = tagsMapper.deleteById(tagId);
            boolean success = result > 0;

            if (success) {
                log.info("标签删除成功: tagId={}", tagId);
            } else {
                log.warn("标签删除失败: tagId={}", tagId);
            }

            return success;

        } catch (Exception e) {
            log.error("删除标签失败: tagId={}", tagId, e);
            throw new RuntimeException("删除标签失败");
        }
    }

    /**
     * 删除菜谱标签关联
     * @param recipeId 菜谱ID
     * @param tagId 标签ID
     * @return
     */
    @Transactional
    public boolean deleteRecipeTag(Long recipeId, Long tagId) {
        log.info("删除菜谱标签关联: recipeId={}, tagId={}", recipeId, tagId);

        try {
            int result = recipeTagsMapper.deleteRecipeTag(recipeId, tagId);
            boolean success = result > 0;

            if (success) {
                log.info("菜谱标签关联删除成功");
            } else {
                log.warn("菜谱标签关联删除失败");
            }

            return success;

        } catch (Exception e) {
            log.error("删除菜谱标签关联失败: ", e);
            throw new RuntimeException("删除关联失败");
        }
    }

    /**
     * 统计标签名称数量
     * @return
     */
    public List<Map<String, Object>> countTagsByName() {
        log.info("统计标签名称数量");

        try {
            List<Map<String, Object>> result = tagsMapper.countTagsByName();
            log.info("统计完成，共 {} 种标签名称", result.size());
            return result;

        } catch (Exception e) {
            log.error("统计标签名称数量失败: ", e);
            throw new RuntimeException("统计标签名称失败");
        }
    }

    /**
     * 根据类型统计标签名称数量
     * @param type 标签类型
     * @return
     */
    public List<Map<String, Object>> countTagsByNameAndType(String type) {
        log.info("根据类型统计标签名称数量: type={}", type);

        if (type == null || type.trim().isEmpty()) {
            throw new IllegalArgumentException("标签类型不能为空");
        }

        try {
            List<Map<String, Object>> result = tagsMapper.countTagsByNameAndType(type);
            log.info("根据类型统计完成，共 {} 种标签名称", result.size());
            return result;

        } catch (Exception e) {
            log.error("根据类型统计标签名称数量失败: ", e);
            throw new RuntimeException("统计标签名称失败");
        }
    }

}




